package clientN

import (
	"encoding/json"
	"log"
	"net/url"
	"time"
	"wxp2p/common"

	"github.com/gorilla/websocket"
)

type ServerClient struct {
	ServerAddr  string
	ClientId    string
	ClientType  common.EClientType
	SendChan    chan common.P2PSignal
	recvChan    chan common.P2PSignal
	WebrtcArray map[int32]*WebrtcAnswer
	BLogin      bool
	doneChan    chan struct{}
	logChan     chan string
	logFunc     func(string)
	runFlag     bool
}

func NewServerClient(addr string, clientId string) *ServerClient {
	sc := ServerClient{}
	sc.BLogin = false
	sc.ClientId = clientId
	sc.ServerAddr = addr
	sc.WebrtcArray = make(map[int32]*WebrtcAnswer)
	sc.ClientType = common.EServerClient
	sc.runFlag = false
	return &sc
}

// 开始
func (sc *ServerClient) Run() {
	if !sc.runFlag {
		go sc.logLoop()
		go sc.recvChanLoop()
		go sc.dialLoop()
		sc.runFlag = true
	}
}

// 关闭
func (sc *ServerClient) StopRun() {
	if sc.runFlag {
		close(sc.doneChan)
		close(sc.recvChan)
		close(sc.logChan)
		sc.runFlag = false
	}
}

// 给界面反馈状态
func (sc *ServerClient) OnLog(f func(log string)) {
	sc.logFunc = f
}

func (sc *ServerClient) logLoop() {
	sc.logChan = make(chan string)
	for lstr := range sc.logChan {
		if sc.logFunc != nil {
			sc.logFunc(lstr)
		}
	}
	common.LogDebug("退出 log loop")
}

// 处理服务器返回的消息
func (sc *ServerClient) recvChanLoop() {
	sc.recvChan = make(chan common.P2PSignal)
	for sig := range sc.recvChan {
		if sig.SigType == common.EClientIdDublite {
			// ID重复
			log.Println(sig.Content)
			sc.logChan <- sig.Content
			sc.StopRun() //可以重新Open
			continue
		} else if sig.SigType == common.ECreateAnswer {
			// 创建webrtc answer
			hp := common.HostPortPeer{}
			json.Unmarshal([]byte(sig.Content), &hp)
			wa := NewWebrtcAnswer(&hp, sc)
			sc.WebrtcArray[wa.WebrtcId] = wa
			wa.Run()
			continue
		} else if sig.SigType == common.ERegOK {
			sc.BLogin = true
			continue
		}
		wr, ok := sc.WebrtcArray[sig.WebrtcId]
		if ok {
			wr.SignalHandler(sig)
		}
	}
}

// 重新连接并注册
func (sc *ServerClient) reDial() {
	common.LogDebug("5秒后重新连接信令服务器")
	time.Sleep(5 * time.Second)
	go sc.dialLoop()
}

// 开始连接，断线自动重连
func (sc *ServerClient) dialLoop() {
	u := url.URL{Scheme: "ws", Host: sc.ServerAddr, Path: "/v2/signal"}
	conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
	if err != nil {
		log.Println("连接到信号服务器失败：", err)
		sc.reDial()
		return
	} else {
		log.Println("成功连接到信号服务器")
		go sc.regClient()
	}

	sc.SendChan = make(chan common.P2PSignal)
	sc.doneChan = make(chan struct{})
	defer func() {
		conn.Close()
		close(sc.SendChan)
		common.LogDebug("退出begin dial loop")
	}()

	readdone := make(chan struct{})
	// 接收信号
	go func() {
		defer close(readdone)
		for {
			sig := common.P2PSignal{}
			err := conn.ReadJSON(&sig)
			if err != nil {
				break
			}
			common.LogDebug("接收到信令:", sig)
			sc.recvChan <- sig
		}
		common.LogDebug("退出 conn read")
	}()
	// 发送信号
	senddone := make(chan struct{})
	go func() {
		defer close(senddone)
		for sig := range sc.SendChan {
			sig.ClientType = sc.ClientType
			sig.ClientId = sc.ClientId
			err := conn.WriteJSON(sig)
			if err != nil {
				break
			}
			common.LogDebug("发送信令:", sig)
		}
		common.LogDebug("退出 send chan")
	}()
	// 阻塞线程退出
	for {
		select {
		case <-readdone: //接收/发送消息出现错误，直接退出线程，或者【重新连接】
			sc.reDial()
			return
		case <-senddone: //接收/发送消息出现错误，直接退出线程，或者【重新连接】
			sc.reDial()
			return
		case <-sc.doneChan:
			return
		}
	}
}

// 注册客户端到服务器
func (sc *ServerClient) regClient() {
	// 注册个名字到服务端
	p2psig := common.P2PSignal{SigType: common.ERegClient, Content: ""}
	sc.SendChan <- p2psig
}
